using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Xml;
using System.ComponentModel;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Common.Utilities.DLR;
using Workflows.Components.Properties;

namespace Workflows.Components
{

    /// <summary>
    /// abstract/base class for all other workflow activity. It encapsulate visual hints,
    /// drag-n-drop onto diagram, instruction and output settings.
    /// </summary>
    [Serializable]
    public abstract class WorkflowComponentBase:ICloneable
    {
        /// <summary>this event is used by designer to update links, property grid display</summary>
        public event ComponentSettingChanged ComponentSettingChangedEvent;

        #region members
        private Guid _ComponentID;
        /// <summary>
        /// GUID at design time. Every time it's droped to designer, a new GUID is
        /// created.
        /// </summary>
        [Browsable(true), Category("General")]
        public Guid ComponentID
        {
            get { return _ComponentID; }
            set
            {
                if(this._ComponentID !=value)
                {
                    _ComponentID = value;
                    if (this.ComponentSettingChangedEvent != null)
                        this.ComponentSettingChangedEvent(this);
                }
                if(this.Instruction !=null)
                    this.Instruction.OwnerComponentID = value;
                if(this.Output !=null)
                    this.Output.OwnerComponentID = value;
            }
        }

        private string _ComponentName;
        /// <summary>default name displayed on both Toolbox and design diagram.</summary>
        [Browsable(true), Category("General")]
        public string ComponentName
        {
            get { return _ComponentName; }
            set
            {
                if(this._ComponentName!=value)
                {
                    _ComponentName = value;
                    if (this.ComponentSettingChangedEvent != null)
                        this.ComponentSettingChangedEvent(this);
                }
            }
        }

        private string _ComponentCategory;
        /// <summary>groupings for workflow component, used to help display on toolbox</summary>
        [Browsable(true), Category("General")]
        public string ComponentCategory
        {
            get { return _ComponentCategory; }
            set
            {
                if(this._ComponentCategory!=value)
                {
                    _ComponentCategory = value;
                    if (this.ComponentSettingChangedEvent != null)
                        this.ComponentSettingChangedEvent(this);
                }
            }
        }

        private WorkflowActivityType _ComponentActivityType;
        /// <summary><para>activity type include trigger, simple, loop, etc.</para></summary>
        [Browsable(true), Category("General")]
        public WorkflowActivityType ComponentActivityType
        {
            get { return _ComponentActivityType; }
            set
            {
                if(this._ComponentActivityType!=value)
                {
                    _ComponentActivityType = value;
                    if (this.ComponentSettingChangedEvent != null)
                        this.ComponentSettingChangedEvent(this);
                }
            }
        }

        private Icon _ComponentIcon;
        /// <summary>16x16 icon displayed on toolbox</summary>
        [Browsable(false), Category("General")]
        [OrmField(false)]
        public Icon ComponentIcon
        {
            get { return _ComponentIcon; }
            set
            {
                 _ComponentIcon = value;
                 if (this.ComponentSettingChangedEvent != null)
                     this.ComponentSettingChangedEvent(this);
            }
        }
        
        private Image _ComponentImage;
        /// <summary>48x48 image (png, gif, bmp, jpg) displayed on design diagram</summary>
        [Browsable(false), Category("General")]
        [OrmField(false)]
        public Image ComponentImage
        {
            get { return _ComponentImage; }
            set
            {
                _ComponentImage = value;
                if (this.ComponentSettingChangedEvent != null)
                    this.ComponentSettingChangedEvent(this);
            }
        }

        /// <summary>an object that encapsulate instruction settings.</summary>
        [Browsable(false), Category("Activity")]
        public abstract InstructionBase Instruction
        { get; set;}

        /// <summary>an object to encapsulate output</summary>
        [Browsable(false), Category("Activity")]
        public abstract ResultBase Output
        { get; set;}

        private bool _Enabled;
        /// <summary>design-time setting, skipped when disabled during job creation process, all data-pipe info associated with it is lost at runtime</summary>
        [Browsable(true), Category("Activity")]
        public bool Enabled
        {
            get
            {
                return this._Enabled;
            }
            set
            {
                this._Enabled = value;
            }
        }


        private string _OutputName;
        /// <summary>
        /// a label attached to output link. default name is {component name} + "
        /// output"
        /// </summary>
        [Browsable(true), Category("Activity")]
        public string OutputName
        {
            get
            {
                if(string.IsNullOrEmpty(this._OutputName))
                {
                    if(this.Output !=null)
                    {
                        this._OutputName = this.Output.GetType().Name;
                    }
                    else
                    {
                        this._OutputName = this.ComponentName + " output";
                    }
                }
                return this._OutputName;
            }
            set
            {
                this._OutputName = value;
            }
        }

        /// <summary>a label attached to error output</summary>
        [Browsable(true), Category("Activity")]
        public string ErrorName
        {
            get
            {
                return this._ComponentName + " error";
            }
        }


        private Single _X;
        /// <summary>left position on the design diagram</summary>
        [Browsable(false), Category("Layout")]
        public Single X
        {
            get { return _X; }
            set
            {
                _X = value;
                if (this.ComponentSettingChangedEvent != null)
                    this.ComponentSettingChangedEvent(this);
            }
        }

        private Single _Y;
        /// <summary>top position of activity on diagram</summary>
        [Browsable(false), Category("Layout")]
        public Single Y
        {
            get { return _Y; }
            set
            {
                _Y = value;
                if (this.ComponentSettingChangedEvent != null)
                    this.ComponentSettingChangedEvent(this);
            }
        }

        private Single _Width;
        /// <summary>width of activity in diagram</summary>
        [Browsable(false), Category("Layout")]
        public Single Width
        {
            get { return _Width; }
            set
            {
                _Width = value;
                if (this.ComponentSettingChangedEvent != null)
                    this.ComponentSettingChangedEvent(this);
            }
        }

        private Single _Height;
        /// <summary>height of activity in diagram</summary>
        [Browsable(false), Category("Layout")]
        public Single Height
        {
            get { return _Height; }
            set
            {
                _Height = value;
                if (this.ComponentSettingChangedEvent != null)
                    this.ComponentSettingChangedEvent(this);
            }
        }

        private string _Description;
        /// <summary>tooltip for activity</summary>
        [Browsable(true), Category("General")]
        public string Description
        {
            get { return _Description; }
            set { _Description = value; }
        }

        private List<Guid> _Dependency;

        /// <summary>list of upstream activity IDs that current activity feed on</summary>
        [OrmField("Dependency",SqlDbType.Text,1000,OrmFieldSerializationMethod.BinarySerialization)]
        public List<Guid> Dependency
        {
            get { return _Dependency; }
            set { _Dependency = value; }
        }
	
        #endregion

        /// <summary>
        /// provide default settings for activity, such as activity type, name, icon, image,
        /// etc.
        /// </summary>
        public WorkflowComponentBase()
        {
            this._ComponentID = Guid.NewGuid();
            this._ComponentName = "New Component";
            this._ComponentCategory = WorkflowComponentCategory.Misc.ToString();
            this._ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this._Description = string.Empty;
            this._ComponentIcon = Resources.otheroptions;
            this._ComponentImage = Resources.engine;

            this._Enabled = true;
            this.Instruction = null;
            this.Output = null;

            this._X = 100;
            this._Y = 100;
            this._Width = 48;
            this._Height = 48;

            this._Description = string.Empty;
            this._Dependency=new List<Guid>();

        }

        #region abstract methods
        /// <summary><para>must implementable method to serialize activity settings to xml</para></summary>
        public virtual XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Component");
            
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.ComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentName", this.ComponentName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Enabled", this.Enabled.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "X", this.X.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Y", this.Y.ToString());

            return xNode;
        }

        /// <summary><para>subclass must implement this method to instantiate activity from xml</para></summary>
        public virtual WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                WorkflowComponentBase wfComponent =(WorkflowComponentBase) Activator.CreateInstance(this.GetType());
                wfComponent.ComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                wfComponent.ComponentName = xNode.Attributes.GetNamedItem("ComponentName").Value;
                wfComponent.Enabled = bool.Parse(XmlDataUtil.GetAttributeValue(xNode, "Enabled", true.ToString()));
                wfComponent.X = float.Parse(XmlDataUtil.GetAttributeValue(xNode, "X", "100"));
                wfComponent.Y = float.Parse(XmlDataUtil.GetAttributeValue(xNode, "Y", "100"));

                return wfComponent;
            }
            else
            {
                throw new Exception("Unable to instantiate component: invalid type specified in xml node");
            }
        }
        #endregion

        #region Implementation of ICloneable

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public object Clone()
        {
            XmlDocument xDoc=new XmlDocument();
            xDoc.LoadXml("<Components></Components>");
            XmlNode root = xDoc.DocumentElement;
            this.Serialize(ref xDoc, ref root);
            WorkflowComponentBase wfComponent = this.Instantiate(root.ChildNodes[0]);
            wfComponent.ComponentID = Guid.NewGuid();
            if (!(wfComponent is WorkflowTriggerBase))
            {
                wfComponent.Instruction.OwnerComponentID = wfComponent.ComponentID;
                wfComponent.Output.OwnerComponentID = wfComponent.ComponentID;
            }
            return wfComponent;
        }

        #endregion
    }
}
